﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Client;
using System.Threading;
using PSE.Deployment.TeamFoundation.Entity;
using System.IO;

namespace PSE.Deployment.TeamFoundation.Communication
{
    /// <summary>
    /// Classe que Manipula um Changeset
    /// </summary>
    public class Changeset : CommunicationBase
    {
        private const string DirectoryMergePath = "Source";

        #region Singleton
        private static Changeset instance;
        protected Changeset()
        {
            Communication.VersionControl.Instance.TraceEvent += (sender, e) => RaiseEventTrace(e);
        }
        public static Changeset Instance
        {
            get
            {
                if (instance == null)
                {
                    Mutex mutex = new Mutex();
                    mutex.WaitOne();

                    if (instance == null)
                        instance = new Changeset();

                    mutex.Close();
                }
                return instance;
            }
        }
        #endregion Singleton

        private PSE.Deployment.TeamFoundation.Entity.Changeset WrapType(Microsoft.TeamFoundation.VersionControl.Client.Changeset changeset)
        {
            if (changeset == null)
                throw new ArgumentNullException("changeset");

            RaiseEventTrace("Convertendo o tipo Microsoft para tipo PSE");
            
            PSE.Deployment.TeamFoundation.Entity.Changeset changesetPSE = new PSE.Deployment.TeamFoundation.Entity.Changeset();
            changesetPSE.Id = changeset.ChangesetId;
            changesetPSE.ArtifactUri = changeset.ArtifactUri.AbsolutePath;

            return changesetPSE;
        }

        /// <summary>
        /// Obtém um changeset por um link
        /// </summary>
        /// <param name="link">link</param>
        /// <returns>changeset</returns>
        public PSE.Deployment.TeamFoundation.Entity.Changeset GetChangeset(Microsoft.TeamFoundation.WorkItemTracking.Client.Link link)
        {
            if (link == null)
                throw new ArgumentNullException("link");

            RaiseEventTrace(string.Format("Obtendo o Changeset por um link: {0}", (link.ArtifactLinkType==null) ? "<<null>>"  : link.ArtifactLinkType.Name));

            Microsoft.TeamFoundation.VersionControl.Client.Changeset changeset = null;

            if (link is Microsoft.TeamFoundation.WorkItemTracking.Client.ExternalLink)
            {
                Microsoft.TeamFoundation.WorkItemTracking.Client.ExternalLink externalLink = (Microsoft.TeamFoundation.WorkItemTracking.Client.ExternalLink)link;
                System.Uri linkUri = new System.Uri(externalLink.LinkedArtifactUri);

                Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer versionControlServer = Communication.VersionControl.Instance.GetVersionControlServer();
                changeset = versionControlServer.ArtifactProvider.GetChangeset(linkUri);
            }

            return this.WrapType(changeset);
        }

        /// <summary>
        /// Obtém um Changeset por um changesetId
        /// </summary>
        /// <param name="workItem">changesetId</param>
        /// <returns>Changeset</returns>
        public Microsoft.TeamFoundation.VersionControl.Client.Changeset GetChangeset(int changesetId)
        {
            if (changesetId <= 0)
                throw new ArgumentException("Invalid changesetId", "changesetId");

            RaiseEventTrace(string.Format("Obtendo o Changeset por um changesetId: {0}", changesetId));

            Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer versionControlServer = Communication.VersionControl.Instance.GetVersionControlServer();
            return versionControlServer.GetChangeset(changesetId);
        }

        /// <summary>
        /// Obtém uma Lista de Changesets por um workItem
        /// </summary>
        /// <param name="workItem">workItem</param>
        /// <returns>Lista de Changesets</returns>
        public List<PSE.Deployment.TeamFoundation.Entity.Changeset> GetChangesets(PSE.Deployment.TeamFoundation.Entity.WorkItem workItem)
        {
            if (workItem == null)
                throw new ArgumentNullException("workItem");

            RaiseEventTrace(string.Format("Obtendo os Changeset por um workitem: {0}", workItem.Id));
            
            List<PSE.Deployment.TeamFoundation.Entity.Changeset> changesets = new List<PSE.Deployment.TeamFoundation.Entity.Changeset>();

            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItemTFS = Communication.WorkItem.Instance.GetWorkItem(workItem); 
            foreach (Microsoft.TeamFoundation.WorkItemTracking.Client.Link link in workItemTFS.Links)
            {
                //Microsoft.TeamFoundation.VersionControl.Client.Changeset changeset = this.GetChangeset(link);
                //if (changeset != null)
                //{
                //    PSE.Deployment.TeamFoundation.Entity.Changeset changesetPSE = this.WrapType(changeset);
                //    changesets.Add(changesetPSE);
                //}

                PSE.Deployment.TeamFoundation.Entity.Changeset changesetPSE = this.GetChangeset(link);
                changesets.Add(changesetPSE);
            }

            return changesets;
        }

        /// <summary>
        /// Formata Changeset
        /// </summary>
        /// <param name="downloadPath">Caminho para Download</param>
        /// <param name="filename">Nome do Arquivo</param>
        /// <returns>Changeset Formatado</returns>
        public string FormatChangeSetItemDownloadPath(string downloadPath, string filename)
        {
            if (string.IsNullOrEmpty(downloadPath))
                throw new ArgumentNullException("downloadPath");

            if (string.IsNullOrEmpty(filename))
                throw new ArgumentNullException("filename");

            
            //Change the TeamFoundation Item format to a file system format.
            string tempFilename = filename.Replace("$", "");
            tempFilename = tempFilename.Replace("/", @"\");
            if (tempFilename.Substring(0, 1).Equals(@"\"))
                tempFilename = tempFilename.Remove(0, 1);

            List<string> directories = tempFilename.Split('\\').ToList();
            int index = directories.FindIndex(
                delegate(string directoryToFind)
                {
                    return directoryToFind.Equals(DirectoryMergePath);
                }
            );
            if (index == -1)
            {
                throw new DirectoryNotFoundException("The item " + filename + " cannot be downloaded because it's path does not contain " + DirectoryMergePath);
            }

            // Remove all directories before DirectoryMergePath (\\Source) path
            directories.RemoveRange(0, index + 1);

            // Join the remaining path
            tempFilename = String.Join("\\", directories.ToArray());

            // Combine the new path with the downloadPath
            tempFilename = Path.Combine(downloadPath, tempFilename);

            RaiseEventTrace(string.Format("Formatando o changeset caminho {0} arquivo {1}. Valor formatado {2}", downloadPath, filename, tempFilename));

            return tempFilename;
        }
        
    }
}
